#include <avr/io.h>
#include <avr/iom164.h> 
#include <avr/interrupt.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#


#define CONTROL 	0x9F
#define CHARACTER	0xFE


void power_on ();
void get_data();

// LCD Functions

void backlight_on (void);
void lcd_on (void);
void lcd_clear (void);
void display_on (void);
void return_home (void);
void cursor_on (void);
void blink_on (void);
void left_to_right (void);
void auto_scroll (void);
void print_lcd (char[] buffer);

// Serial Functions

void serial_init();
void lcd_transmit(unsigned char data);
char lcd_receive();
void lcd_flush();
void obd_transmit(unsigned char data);
char obd_receive();

int main(void){
	serial_init(); // Initialize Serial
	lcd_init();
	power_on(); // Turn Power Light On
	while(1){
		get_data();
	}		
} 

void power_on (){
	DDRA=0xff;
	//DDRD=0xff; Saw this in the code, couldn't tell if we need it
	PORTA = 0x01;
}

void get_data (){
	int flag = 0;
	unsigned char data, data1;
	PORTA = 0x01;
			lcd_transmit(CONTROL);
			lcd_transmit(0x6C);
			// Set cursor

			/*lcd_transmit(CONTROL);
			lcd_transmit(0xFF);
			PORTA = 0x06;
			while( (data = lcd_receive()) != 0x5A);
			int i;
			for(i=0;i<10000;i++){}
			lcd_transmit(0x80);
			lcd_transmit(0x00);
						
			// Set cursor again

/*			lcd_transmit(CONTROL);
			lcd_transmit(0xFF);
			while( (data = lcd_receive()) != 0x5B);
			lcd_transmit(0x80);
			lcd_transmit(0x00);*/

			lcd_transmit(CHARACTER);
			while(1){
				lcd_transmit(0x23);
				PORTA = 0x07;
			} 
			
			PORTA = 0x07;
			while(1);
		}
	}	 
}

void lcd_init(void){
	int begin_call;
	begin_call = lcd_receive();
	if (begin_call == 0xA3){
		lcd_transmit(0x83);
		lcd_transmit(0xA5);
		begin_call = lcd_receive();
		if (begin_call == 0xAA){
			backlight_on();
			lcd_on();
			lcd_clear();
			display_on();
			return_home();
			cursor_on();
			blink_on();
			left_to_right();
			auto_scroll();
			
			// HAVE TO DOUBLE CHECK WHAT THE THING BELOW ACTUALLY DOES
			
			lcd_transmit(CONTROL);
			lcd_transmit(0x6C);
		}	
	}
}	

void backlight_on (void){

/*
*	Purpose: Turn the backlight on the LCD
*	Input: None
*   Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x81);
}	

void lcd_on (void){

/*
*	Purpose: Turn the LCD on
*   Input: None
*   Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x83);
}	

void lcd_clear (void){

/*
*	Purpose: Clears the LCD
*   Input: None
*	Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x65);
}	

void display_on (void){

/*
*	Purpose: Turns the LCD display on
*	Input: None
*	Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x64);
}	
	
void return_home (void){

/*
*	Purpose: Returns the LCD cursor to the beginning of the LCD
*	Input: None
*	Output: None
*/	
	lcd_transmit(CONTROL);
	lcd_transmit(0x61);
}	

void cursor_on (void){

/*
*	Purpose: Turns the LCD cursor on
*	Input: None
*	Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x67);
}	

void blink_on (void){

/*
*	Purpose: Turns a LCD blinking cursor on
*	Input: None
*	Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x69);
}

void left_to_right (void){
	
/*
*	Purpose: Causes the LCD writing to go from left to right
*	Input: None
*	Output: None
*/				

	lcd_transmit(CONTROL);
	lcd_transmit(0x70);
}	

void auto_scroll (void){

/*
*	Purpose: Causes the cursor to write next to the previous character on the LCD
*	Input: None
*   Output: None
*/

	lcd_transmit(CONTROL);
	lcd_transmit(0x6D);
}	
	
void print_lcd (char[] buffer){

/*
*	Purpose: Prints string of characters to the LCD
*	Input: String of characters desired
*	Output: Nothing
*/

	int i;
	for(i=0;i<sizeof(buffer);i++){
		lcd_transmit(buffer[i]);
	}
	return;
}
	
void serial_init (void){

/*
*	Purpose: Initializes serial on both USART busses
*	Input: None
*	Output: None
*/


//	PRR0 |= (0<<PRUSART1)|(0<<PRUSART0); // Power Reduction Off

	//USART0

	UCSR0A |= (1<<U2X0);				// Double speed for better accuracy
	UCSR0B |= (1<<RXEN0)|(1<<TXEN0);	// Reading and Writing Turned on	
	UCSR0C |= (1<<USBS0)|(3<<UCSZ00);	// 8 Bits 2 Stop Bits
	UBRR0H = 0;							// 9600 Baud
	UBRR0L = 12;

	// USART1

	UCSR1A |= (1<<U2X1);				// Double speed for better accuracy
	UCSR1B |= (1<<RXEN1)|(1<<TXEN1); 	// Allow transmit and receive
	UCSR1C |= (1<<USBS1)|(3<<UCSZ10); 	// 8 Bit 2 Stop Bits
	UBRR1H = 0;
	UBRR1L = 12; 						// 9600 Baud
}

void lcd_transmit (unsigned char data){

/*
*	Purpose: Transmit data to the LCD
*	Input: Character of data to send to LCD
*	Output: Nothing
*/

	while( !(UCSR1A & (1<<UDRE1)));	// Waits for the bus to be empty
	UDR1 = data;					// When empty load the data
}

char lcd_receive (void){

/*
*	Purpose: Receive data from the LCD
*	Input: Nothing
*	Output: Character from the LCD
*/

	while (!(UCSR1A & (1<<RXC1)));	// Waits for the bus to have data
	return UDR1;					
}	

void obd_transmit (unsigned char data){

/*
*	Purpose: Transmit data to the OBDII bus
*	Input: Character of data to send to OBDII bus
*	Output: Nothing
*/


	while( !(UCSR0A & (1<<UDRE0)));
	UDR0 = data;
}

char obd_receive (void){

/*
*	Purpose: Receive data from the OBDII bus
*	Input: Nothing
*	Output: Character from the OBDII bus
*/

	while (!(UCSR0A & (1<<RXC0)));
	return UDR0;
}

void lcd_flush (void){
	char tmp;
	while (UCSR1A & (1<<RXC1) ) tmp = UDR1;
}


